﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microhard.WeixinMP.Interfaces;
using System.Xml.Linq;
using System.Web;

namespace Microhard.WeixinMP.Models
{
    [WeixinDataAtr("xml")]
    public class WeixinBaseData<T> where T : new()
    {
        public XDocument _xd;
        protected string _weixinReceiveXML;

        public WeixinBaseData(string weixinReceiveXML)
        {
            _xd = XDocument.Parse(weixinReceiveXML);
            _weixinReceiveXML = weixinReceiveXML;
        }

        public WeixinBaseData(XDocument xml)
        {
            _xd = xml;
        }

        public WeixinBaseData()
        {

        }

        public bool GoToNextWeixinRobotImpl { set; get; }

        /// <summary>
        /// 开发者微信号
        /// </summary> 
        [WeixinDataAtr("ToUserName", (int)WeixinXMLSorting.First, XmlValueType.StringValue, true)]
        public string ToUserName { set; get; }
        /// <summary>
        /// 发送方帐号（一个OpenID）
        /// </summary>
        [WeixinDataAtr("FromUserName", 2, XmlValueType.StringValue, true)]
        public string FromUserName { set; get; }
        /// <summary>
        /// 消息创建时间 （整型）
        /// </summary>
        [WeixinDataAtr("CreateTime", 3, XmlValueType.LongValue, true)]
        public string CreateTime { set; get; }
        /// <summary>
        /// text
        /// </summary>
        [WeixinDataAtr("MsgType", 4, XmlValueType.StringValue, true)]
        public string MsgType { set; get; }
        /// <summary>
        /// 内容
        /// </summary>
        [WeixinDataAtr(5, XmlValueType.DynmicValue, true)]
        public T Content { set; get; }
        /// <summary>
        /// 消息id，64位整型
        /// </summary>
        [WeixinDataAtr("MsgId", (int)WeixinXMLSorting.Last, XmlValueType.LongValue, false)]
        public string MsgId { set; get; }

        /// <summary>
        /// 位0x0001被标志时，星标刚收到的消息。
        /// </summary>
        [WeixinDataAtr("FuncFlag", (int)WeixinXMLSorting.Last, XmlValueType.LongValue, true)]
        public string FuncFlag { set; get; }

        /// <summary>
        /// 获得weixi返回xml中的固定内容
        /// </summary>
        /// <returns></returns>
        protected virtual void GetConstProperties()
        {
            this.ToUserName = _xd.Element("xml").Element("ToUserName").Value;
            this.CreateTime = _xd.Element("xml").Element("CreateTime").Value;
            this.FromUserName = _xd.Element("xml").Element("FromUserName").Value;
            this.MsgType = _xd.Element("xml").Element("MsgType").Value;
            if (this.MsgType != WeixinMsgType.Event)
            {
                this.MsgId = _xd.Element("xml").Element("MsgId").Value;
            }
        }
        /// <summary>
        /// 获得微信返回xml中的变动内容（根据msgtype觉得是那种变动的内容）
        /// </summary>
        /// <returns></returns>
        protected virtual T GetDynmicProperty()
        {
            T result = new T();
            Type type = result.GetType();
            var properties = type.GetProperties();
            foreach (var p in properties)
            {
                var atrs = p.GetCustomAttributes(typeof(WeixinDataAtr), false);
                if (atrs != null && atrs.Count() > 0)
                {
                    var custProty = atrs.First() as WeixinDataAtr;
                    if (custProty != null && _xd.Element("xml") != null)
                    {
                        var value = _xd.Element("xml").Element(custProty.XmlElement).Value;
                        p.SetValue(result, value, null);
                    }
                }
            }
            return result;
        }

        protected virtual string BuildPropertiesToXML(object model)
        {
            //TODO验证是否在微信允许的回复类型范围内

            StringBuilder doc = new StringBuilder();
            if (model == null)
                return doc.ToString();

            Type type = model.GetType();
            //获得xml根节点
            var headerAttrs = type.GetCustomAttributes(typeof(WeixinDataAtr), false);
            string root = null;
            if (headerAttrs != null && headerAttrs.Count() > 0)
            {
                var attr = headerAttrs.First() as WeixinDataAtr;
                root = attr.XmlElement;
            }

            var properties = type.GetProperties();
            List<BuildXMLModel> allAtrs = new List<BuildXMLModel>();
            foreach (var p in properties)
            {
                var atrs = p.GetCustomAttributes(typeof(WeixinDataAtr), false);
                if (atrs != null && atrs.Count() > 0)
                {
                    var custProty = atrs.First() as WeixinDataAtr;
                    if (custProty != null && custProty.UsingInResponse)
                    {
                        allAtrs.Add(new BuildXMLModel
                        {
                            DataAttr = custProty,
                            Property = p
                        });
                    }
                }
            }
            var sortedAttrs = allAtrs.OrderBy(p => p.DataAttr.OrderForBuildXML).ToList();
            sortedAttrs.ForEach(item =>
            {
                object value = item.Property.GetValue(model, null);
                string row = null;
                switch (item.DataAttr.ValueType)
                {
                    case XmlValueType.LongValue:
                        row = new XElement(item.DataAttr.XmlElement, value).ToString();
                        break;
                    case XmlValueType.StringValue:
                        string strValue = string.Empty;
                        if (value != null)
                            strValue = value.ToString();
                        row = new XElement(item.DataAttr.XmlElement,
                                                   new XCData(strValue)).ToString();
                        break;
                    case XmlValueType.DynmicValue:
                        row = this.BuildPropertiesToXML(value);
                        break;
                    case XmlValueType.ListValue:
                        row = this.BuildListObjectToXML(value, item.DataAttr.XmlElement);
                        break;
                }
                if (!string.IsNullOrEmpty(row))
                {
                    doc.AppendLine(row);
                }
            });
            if (root != null)
            {
                return string.Format("<{0}>{1}</{0}>", root, doc.ToString());
            }
            return doc.ToString();
        }

        private string BuildListObjectToXML(object model, string xmlRoot)
        {
            //集合排序
            StringBuilder result = new StringBuilder();
            List<WeixinNewsItem_Response> list = model as List<WeixinNewsItem_Response>;
            if (list == null)
                return result.ToString();
            list = list.OrderBy(l => l.Order).ToList();

            //组装为xml        
            list.ForEach(item =>
            {
                var strdocItem = this.BuildPropertiesToXML(item);
                if (!string.IsNullOrEmpty(strdocItem))
                {
                    result.AppendLine(strdocItem);
                }
            });

            return string.Format("<{0}>{1}</{0}>", xmlRoot, result.ToString());
        }


        public WeixinBaseData<T> ToModel()
        {
            this.GetConstProperties();
            this.Content = this.GetDynmicProperty();
            return this;
        }

        public override string ToString()
        {
            string strXML = this.BuildPropertiesToXML(this);
            var xd = XDocument.Parse(strXML);
            return xd.ToString();
        }

        public string EncodeWeixinToUserName
        {
            get
            {
                return HttpUtility.UrlEncode(this.ToUserName);
            }
        }
    }
}
